package com.excel.service.excel;


import cn.hutool.core.util.ObjectUtil;
import com.corpgovernment.api.applytrip.enums.ApplyTripEmployeeEnum;
import com.corpgovernment.common.enums.CardEnum;
import com.corpgovernment.common.enums.GenderEnum;
import com.corpgovernment.common.enums.NationalityEnum;
import com.corpgovernment.common.enums.PhoneCountryCodeEnum;
import com.corpgovernment.organization.Bo.SyncEmployeeInfoBo;
import com.corpgovernment.organization.util.ExcelUtils;
import com.corpgovernment.organization.util.IdCardUtil;
import com.corpgovernment.organization.util.StrUtils;
import com.corpgovernment.organization.vo.EmployeeCardTypeInfoColumnVO;
import com.corpgovernment.organization.vo.EmployeeInfoExcelColumnVO;
import com.ctrip.corp.obt.async.redis.RedisClientDelegate;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.excel.entity.db.PubImpExcelJdLog;
import com.excel.entity.db.PubImpExcelValidLog;

import com.excel.model.ExcelImportConfig;
import com.excel.mq.Bo.EmployEventBo;
import com.excel.mq.ExcelMQProducer;
import com.excel.service.IPubImpExcelValidLogService;
import com.excel.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.corpgovernment.common.enums.GenderEnum.F;
import static com.corpgovernment.common.enums.GenderEnum.M;

/**
 * 员工
 *
 * @author hc
 */
@Service
@Slf4j
public class EmployExcelImportProcessor<T> implements ExcelImportProcessor<PubImpExcelValidLog,SyncEmployeeInfoBo,PubImpExcelJdLog,T> {

    @Autowired
    private ExcelUtils excelUtils;
    @Autowired
    private ExcelMQProducer employeeMQProducer;
    @Resource
    private RedisClientDelegate redisClientDelegate;
    @Autowired
    private IPubImpExcelValidLogService excelValidLogService;
    @Autowired
    private OssService ossService;

    private static final String REDIS_KEY_PREFIX = "excel:employ:";


    @Override
    public List<SyncEmployeeInfoBo> assembleListFromExcel(PubImpExcelJdLog pubImpExcelJdLog) {

        // 获取excel资源
        XSSFWorkbook workBook = ossService.getExcelByOss(pubImpExcelJdLog);

        XSSFSheet sheetOrg = workBook.getSheet("员工");
        List<EmployeeInfoExcelColumnVO> employeeInfo = excelUtils.getBeanListFromExcelTwo(sheetOrg, EmployeeInfoExcelColumnVO.class);

        //获取证件数据
        XSSFSheet sheetDelivery = workBook.getSheet("证件");
        List<EmployeeCardTypeInfoColumnVO> empCardType = excelUtils.getBeanListFromExcel(sheetDelivery, EmployeeCardTypeInfoColumnVO.class);

        employeeInfo.forEach(StrUtils::fieldRemoveWarp);
        empCardType.forEach(StrUtils::fieldRemoveWarp);

        //将证件信息——>Map
        Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap = empCardType.stream().
                filter(item -> Objects.nonNull(item) && StringUtils.isNotBlank(item.getUid())).collect(Collectors.groupingBy(item -> item.getUid()));

        confirmGenderAndBirthDay(empCardMap, employeeInfo);
        List<SyncEmployeeInfoBo> empList = new ArrayList<>();

        //将员工绑定证件
        for (EmployeeInfoExcelColumnVO item : employeeInfo) {
            SyncEmployeeInfoBo employeeInfoBo =  buildEmployeeInfoBo(empCardMap, item);
            empList.add(employeeInfoBo);
        }
        log.info( "组装后数据：{}", JsonUtils.toJsonString(empList));
        return empList;
    }



    @Override
    public BizImportResult<PubImpExcelValidLog,SyncEmployeeInfoBo> checkExcelData(List<SyncEmployeeInfoBo> list) {

        BizImportResultImpl<PubImpExcelValidLog, SyncEmployeeInfoBo> result = new BizImportResultImpl<>();

        List<PubImpExcelValidLog> errorList = new ArrayList<>();
        List<SyncEmployeeInfoBo> dataList = new ArrayList<>();
        for (SyncEmployeeInfoBo item : list) {
            PubImpExcelValidLog errorLog = new PubImpExcelValidLog();
            errorLog.setRowId(item.getLineNo());
            if (StringUtils.isBlank(item.getUid())) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("员工编号为空");
                errorList.add(errorLog);
            }
            if (item.getUid().length() > 50) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("员工编号长度大于50");
                errorList.add(errorLog);
            }
            if (ObjectUtil.isNotEmpty(item.getPostId()) && !item.getPostId().toString().matches("^[0-9]*$")) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("员工职级ID必须为整数");
                errorList.add(errorLog);
            }
            if (StringUtils.isNotBlank(item.getNationality()) && Objects.isNull(NationalityEnum.getByCode(item.getNationality()))) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("国籍的国家二字码错误");
                errorList.add(errorLog);
            }
            if (StringUtils.isNotBlank(item.getGender()) && Objects.isNull(GenderEnum.getByCode(item.getGender()))) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("性别错误");
                errorList.add(errorLog);
            }
            if (StringUtils.isNotBlank(item.getCountryCode()) && Objects.isNull(PhoneCountryCodeEnum.getByCountryCode(item.getCountryCode()))) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("手机国家码错误");
                errorList.add(errorLog);
            }
            if ((StringUtils.isBlank(item.getCountryCode()) || PhoneCountryCodeEnum.CN.getCountryCode().equals(item.getCountryCode())) &&
                    (StringUtils.isBlank(item.getMobilePhone()) || item.getMobilePhone().length() > 11)) {
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setValidTip("手机号码填写错误");
                errorList.add(errorLog);
            }
            dataList.add(item);
        }

        result.setErrorList(errorList);
        result.setDataList(dataList);
        return result;
    }

    @Override
    public BizImportResult<PubImpExcelValidLog,SyncEmployeeInfoBo> checkDbData(List<SyncEmployeeInfoBo> list) {
        return null;
    }

    @Override
    public BizImportResult<PubImpExcelValidLog,SyncEmployeeInfoBo> checkDataPermission(List<SyncEmployeeInfoBo> list) {
        return null;
    }

    @Override
    public BizImportResult<PubImpExcelValidLog,SyncEmployeeInfoBo> tempWrite(List<SyncEmployeeInfoBo> list) {
        return null;
    }

    @Override
    public void writeErrorLog(List<PubImpExcelValidLog> errors, PubImpExcelJdLog pubImpExcelJdLog) {
        for (int i = 0; i < errors.size(); i++) {
            errors.get(i).setJdlogId(pubImpExcelJdLog.getId());
        }
        excelValidLogService.saveBatch(errors);
    }

    @Override
    public String getTag() {
        return "employ";
    }

    @Override
    public ExcelImportConfig getConfig() {
        ExcelImportConfig config = new ExcelImportConfig();
        config.setIsSharding(true);
        config.setIgnoreHeader(true);
        config.setDelayLevel(9);
        config.setRollBackType(2);
        config.setShardingNum(10);
        return config;
    }

    @Override
    public void sendMqWithCache(PubImpExcelJdLog pubImpExcelJdLog, List<List<SyncEmployeeInfoBo>> partitions) {
        for (int i = 0; i < partitions.size(); i++) {
            List<SyncEmployeeInfoBo> list = partitions.get(i);
            String redisKey = REDIS_KEY_PREFIX + pubImpExcelJdLog.getPcNum() + "_" + i;
            List<String> lineList = list.stream()
                    .map(SyncEmployeeInfoBo::getLineNo)
                    .collect(Collectors.toList());
            EmployEventBo event = new EmployEventBo();
            event.setLines(lineList);
            event.setTaskId(pubImpExcelJdLog.getPcNum());
            event.setRedisKey(redisKey);
            event.setTags(getTag());
            event.setShardingIndex(i);
            event.setShardingTotal(partitions.size());
            employeeMQProducer.sendEmployeeBasic(event);

            for (int j = 0; j < list.size(); j++) {
                SyncEmployeeInfoBo columnVO = list.get(j);
                this.redisClientDelegate.withHashCommandsClient(c -> {
                            c.put(redisKey, columnVO.getLineNo(), columnVO);
                        }
                );
            }
        }
    }

    @Override
    public void sendDelayCheckMq(PubImpExcelJdLog pubImpExcelJdLog) {
        EmployEventBo event = new EmployEventBo();
        event.setTaskId(pubImpExcelJdLog.getPcNum());
        event.setTags(getTag());
        employeeMQProducer.sendEmployeeCheckDelay(event, getConfig().getDelayLevel());
    }




    private void confirmGenderAndBirthDay(Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap, List<EmployeeInfoExcelColumnVO> employeeInfo) {
        employeeInfo.forEach(e ->{
            if (empCardMap.containsKey(e.getUid()) && CollectionUtils.isNotEmpty(empCardMap.get(e.getUid()))) {
                // 特定类型的证件号码转大写
                empCardMap.get(e.getUid()).forEach(k ->{
                    if (CardEnum.needUpperCaseCard(k.getCardType())){
                        k.setCardNo(k.getCardNo().toUpperCase());
                    }
                });
                //根据身份证号码确定性别生日信息
                List<EmployeeCardTypeInfoColumnVO> idCards = empCardMap.get(e.getUid()).stream().filter(k -> CardEnum.ID_CARD.getName().equals(k.getCardType())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(idCards)) {
                    String cardNo = idCards.get(0).getCardNo();
                    e.setBirthday(IdCardUtil.getBirth(cardNo));
                    e.setGender(IdCardUtil.getGender(cardNo));
                }
            }
        });
    }



    private  SyncEmployeeInfoBo buildEmployeeInfoBo(Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap, EmployeeInfoExcelColumnVO item) {
        SyncEmployeeInfoBo employeeInfoBo = new SyncEmployeeInfoBo();

        NationalityEnum nation = NationalityEnum.getByDesc(Optional.ofNullable(item.getNationality()).orElse(NationalityEnum.CN.getCode()));
        if(nation !=null){
            item.setNationality(nation.getCode());
        }else {
            item.setNationality(NationalityEnum.CN.getCode());
        }

        employeeInfoBo.setLineNo(item.getLineNo());
        employeeInfoBo.setIsDelete(false);
        employeeInfoBo.setUid(item.getUid());
        employeeInfoBo.setName(item.getName());
        employeeInfoBo.setLastName(item.getLastName());
        employeeInfoBo.setFirstName(item.getFirstName());
        if (StringUtils.isEmpty(item.getCountryCode())) {
            employeeInfoBo.setCountryCode(PhoneCountryCodeEnum.CN.getCountryCode());
        } else {
            int contryCode = item.getCountryCode().indexOf("+");
            employeeInfoBo.setCountryCode(contryCode>-1? item.getCountryCode().substring(contryCode):"+86");
        }
        employeeInfoBo.setMobilePhone(item.getMobilePhone());
        // employeeInfoBo.setPassword(item.getPassword());
        employeeInfoBo.setBirthday(item.getBirthday());
        employeeInfoBo.setGender(F.getDesc().equals(item.getGender()) ? F.getCode() : M.getCode());
        employeeInfoBo.setEmail(item.getEmail());
        NationalityEnum nationalityEnum = Optional.ofNullable(NationalityEnum.getByCode(item.getNationality())).orElse(NationalityEnum.CN);
        employeeInfoBo.setNationality(nationalityEnum.getCode());
        employeeInfoBo.setCreditCardNumbers(null);
        employeeInfoBo.setBusinessCode(item.getBusinessCode());
        employeeInfoBo.setPostName(item.getPostName());
        employeeInfoBo.setPostId(StringUtils.isNotBlank(item.getPostId()) ? Long.valueOf(item.getPostId()) : null);

        List<SyncEmployeeInfoBo.SyncEmployeeCardInfoBo> idCardInfoBoList = new ArrayList<>();
        List<EmployeeCardTypeInfoColumnVO> idCardInfoList = empCardMap.get(item.getUid());
        if (CollectionUtils.isNotEmpty(idCardInfoList)) {
            for (EmployeeCardTypeInfoColumnVO carInfo : idCardInfoList) {
                SyncEmployeeInfoBo.SyncEmployeeCardInfoBo cardInfoBo = new SyncEmployeeInfoBo.SyncEmployeeCardInfoBo();
                cardInfoBo.setLineNo(carInfo.getLineNo());
                cardInfoBo.setCardType(carInfo.getCardType());
                cardInfoBo.setCardNo(carInfo.getCardNo());
                cardInfoBo.setTimeLimit(carInfo.getTimeLimit());
                cardInfoBo.setUid(carInfo.getUid());
                cardInfoBo.setPlaceOfIssue(carInfo.getPlaceOfIssue());
                idCardInfoBoList.add(cardInfoBo);
            }
        }
        employeeInfoBo.setCardInfoList(idCardInfoBoList);
        employeeInfoBo.setRoleName(item.getRoleName());
        employeeInfoBo.setEmployeeType(ApplyTripEmployeeEnum.getCodeByName(item.getEmployeeType()));
        employeeInfoBo.setManageUid(item.getManageUid());
        employeeInfoBo.setJobCode(item.getJobCode());
        employeeInfoBo.setJobName(item.getJobName());
        return employeeInfoBo;
    }


}
